package luxing.util;

import java.beans.PropertyDescriptor;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Map;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.criterion.Disjunction;
import org.hibernate.criterion.Restrictions;

import luxing.exception.BusinessException;
import luxing.hibernate.CriteriaQuery;
import luxing.hibernate.QueryRuleEnum;

/**
 * 
 * @author zzc
 * @de
 * 
 */
public class CriteriaQueryUtil {

	public static void assembling(CriteriaQuery cq, Object obj, Map<String, String[]> parameterMap) {
		assemblingJoinAlias(cq, obj, parameterMap, null);
	}

	/**
	 * 添加Alias别名的查询
	 * 
	 * @date 2014年1月19日
	 * @param cq
	 * @param obj
	 * @param parameterMap
	 * @param alias
	 */
	private static void assemblingJoinAlias(CriteriaQuery cq, Object obj, Map<String, String[]> parameterMap,
			String alias) {
		SimpleDateFormat time = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
		PropertyDescriptor properties[] = PropertyUtils.getPropertyDescriptors(obj);
		String name, type, aliasName;
		for (int i = 0; i < properties.length; i++) {
			name = properties[i].getName();
			type = properties[i].getPropertyType().toString();
			aliasName = (alias == null ? "" : alias + ".") + properties[i].getName();
			try {
				if (isUselessField(name) || !PropertyUtils.isReadable(obj, name)) {
					continue;
				}
				// 添加 判断是否有区间值
				String beginValue = null;
				String endValue = null;
				if (parameterMap != null && parameterMap.containsKey(name + "_begin")) {
					beginValue = parameterMap.get(name + "_begin")[0].trim();
				}
				if (parameterMap != null && parameterMap.containsKey(name + "_end")) {
					endValue = parameterMap.get(name + "_end")[0].trim();
				}
				Object value = PropertyUtils.getSimpleProperty(obj, name);
				// 根据类型分类处理
				if (type.contains("class java.lang") || type.contains("class java.math")) {
					// 租户过滤
					if (name.equals("tenantId")) {
						assemblingCriteria(cq, aliasName, QueryRuleEnum.EQ, LoginUserUtil.getLoginUser().getTenantId());
					}
					// 查询拼装
					if (ObjectUtil.isNotEmpty(value)) {
						if (value.toString().endsWith(",")) {
							// checkbox复选框
							String[] vals = value.toString().replace(",,", ",").split(",");
							Disjunction dis = Restrictions.disjunction();// 替代多个Restrictions.or
							for (String val : vals) {
								if (StringUtils.isNotBlank(val)) {
									dis.add(Restrictions.eq(name, val));
								}
							}
							cq.add(dis);
						} else {
							// 输入框,下拉框
							assemblingCriteria(cq, aliasName, QueryRuleEnum.LIKE, value);
						}

					} else if (parameterMap != null) {
						// 范围
						Object beginValue_ = null, endValue_ = null;
						if ("class java.lang.Integer".equals(type)) {
							if (!"".equals(beginValue) && null != beginValue)
								beginValue_ = Integer.parseInt(beginValue);
							if (!"".equals(endValue) && null != endValue)
								endValue_ = Integer.parseInt(endValue);
						} else if ("class java.math.BigDecimal".equals(type)) {
							if (!"".equals(beginValue) && null != beginValue)
								beginValue_ = new BigDecimal(beginValue);
							if (!"".equals(endValue) && null != endValue)
								endValue_ = new BigDecimal(endValue);
						} else if ("class java.lang.Short".equals(type)) {
							if (!"".equals(beginValue) && null != beginValue)
								beginValue_ = Short.parseShort(beginValue);
							if (!"".equals(endValue) && null != endValue)
								endValue_ = Short.parseShort(endValue);
						} else if ("class java.lang.Long".equals(type)) {
							if (!"".equals(beginValue) && null != beginValue)
								beginValue_ = Long.parseLong(beginValue);
							if (!"".equals(endValue) && null != endValue)
								endValue_ = Long.parseLong(endValue);
						} else if ("class java.lang.Float".equals(type)) {
							if (!"".equals(beginValue) && null != beginValue)
								beginValue_ = Float.parseFloat(beginValue);
							if (!"".equals(endValue) && null != endValue)
								endValue_ = Float.parseFloat(endValue);
						} else {
							beginValue_ = beginValue;
							endValue_ = endValue;
						}
						assemblingCriteria(cq, aliasName, QueryRuleEnum.GE, beginValue_);
						assemblingCriteria(cq, aliasName, QueryRuleEnum.LE, endValue_);
					}
				} else if ("class java.util.Date".equals(type) || "class java.sql.Timestamp".equals(type)) {
					// 日期
					if (StringUtils.isNotBlank(beginValue)) {
						if (beginValue.length() == 19) {
							cq.ge(aliasName, time.parse(beginValue));
						} else if (beginValue.length() == 10) {
							cq.ge(aliasName, time.parse(beginValue + " 00:00:00"));
						}
					}
					if (StringUtils.isNotBlank(endValue)) {
						if (endValue.length() == 19) {
							cq.le(aliasName, time.parse(endValue));
						} else if (endValue.length() == 10) {
							// 对于"yyyy-MM-dd"格式日期，因时间默认为0，故此添加"
							// 23:23:59"并使用time解析，以方便查询日期时间数据
							cq.le(aliasName, time.parse(endValue + " 23:23:59"));
						}
					}
					if (isNotEmpty(value)) {
						cq.eq(aliasName, value);
					}
				} else if (!ObjectUtil.isJavaClass(properties[i].getPropertyType())) {
					Object param = PropertyUtils.getSimpleProperty(obj, name);
					if (isNotEmpty(param) && itIsNotAllEmpty(param)) {
						// 如果是实体类,创建别名,继续创建查询条件
						cq.createAlias(aliasName, aliasName.replaceAll("\\.", "_"));
						assemblingJoinAlias(cq, param, parameterMap, aliasName.replaceAll("\\.", "_"));
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	private static boolean isUselessField(String name) {
		return "class".equals(name) || "ids".equals(name) || "page".equals(name) || "rows".equals(name)
				|| "sort".equals(name) || "order".equals(name);
	}

	/**
	 * 判断是不是空
	 */
	private static boolean isNotEmpty(Object value) {
		return value != null && !"".equals(value);
	}

	/**
	 * 判断这个类是不是所以属性都为空
	 * 
	 * @param param
	 * @return
	 */
	private static boolean itIsNotAllEmpty(Object param) {
		boolean isNotEmpty = false;
		try {
			PropertyDescriptor origDescriptors[] = PropertyUtils.getPropertyDescriptors(param);
			String name;
			for (int i = 0; i < origDescriptors.length; i++) {
				name = origDescriptors[i].getName();
				if ("class".equals(name) || !PropertyUtils.isReadable(param, name)) {
					continue;
				}
				if (Map.class.isAssignableFrom(origDescriptors[i].getPropertyType())) {
					Map<?, ?> map = (Map<?, ?>) PropertyUtils.getSimpleProperty(param, name);
					if (map != null && map.size() > 0) {
						isNotEmpty = true;
						break;
					}
				} else if (Collection.class.isAssignableFrom(origDescriptors[i].getPropertyType())) {
					Collection<?> c = (Collection<?>) PropertyUtils.getSimpleProperty(param, name);
					if (c != null && c.size() > 0) {
						isNotEmpty = true;
						break;
					}
				} else if (ObjectUtil.isNotEmpty(PropertyUtils.getSimpleProperty(param, name))) {
					isNotEmpty = true;
					break;
				}
			}
		} catch (Exception e) {
			throw new BusinessException(e);
		}
		return isNotEmpty;
	}

	private static void assemblingCriteria(CriteriaQuery cq, String name, QueryRuleEnum rule, Object value) {
		if (value == null || rule == null) {
			return;
		}
		switch (rule) {
		case GE:
			cq.ge(name, value);
			break;
		case LE:
			cq.le(name, value);
			break;
		case EQ:
			cq.eq(name, value);
			break;
		case LIKE:
			cq.like(name, "%" + value + "%");
			break;
		default:
			break;
		}
	}

}
